# Reksio - Memory Map Editor
# Copyright (C) 2023 CERN
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# In applying this licence, CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization or
# submit itself to any jurisdiction.

import reksio


def validate(node):
	result = True
	errors = []
	filename_attr = node.getAttribute('filename')
	if filename_attr is not None:
		# no size allowed
		size_attr = node.getAttribute('size')
		if size_attr is not None:
			result = False
			errors.append(f"If filename is present, a submap cannot have size")
		# no interface allowed
		interface_attr = node.getAttribute('interface')
		if interface_attr is not None:
			result = False
			errors.append(f"If filename is present, a submap cannot have interface")
		# if include is set to false, then x-hdl/busgroup should be set to the same value as the submap's memory-map
		# x-hdl/busgroup attribute (default False). Else a warning can be issued
		include_attr = node.getAttribute('include')

		if include_attr is not None:
			include_attr_val = str(include_attr.value).lower()
		else:
			include_attr_val = "false"  # default

		if include_attr_val == "false":
			submap_busgroup = node.getAttribute(['x-hdl', 'busgroup'])

			if submap_busgroup is not None:
				submap_busgroup_val = str(submap_busgroup.value).lower()
			else:
				submap_busgroup_val = "false"

			child_map = node.getChildByType('memory-map')
			if child_map is not None:
				child_map_busgroup = child_map.getAttribute(['x-hdl', 'busgroup'])
				if child_map_busgroup is not None:
					child_map_busgroup_val = str(child_map_busgroup.value).lower()
				else:
					child_map_busgroup_val = "false"

				if child_map_busgroup_val != submap_busgroup_val:
					result = False
					errors.append(f"If filename is present, submap's x-hdl/busgroup (default: False) should match it's "
								  f"memory-map x-hdl/busgroup")
	else:
		# filename is not present

		# must have size attribute
		size_attr = node.getAttribute('size')
		if size_attr is None:
			result = False
			errors.append(f"If filename is not present, a submap must have a size")
		# must have interface attribute
		interface_attr = node.getAttribute('interface')
		if interface_attr is None:
			result = False
			errors.append(f"If filename is not present, a submap must have an interface")
		# no include attribute allowed
		include_attr = node.getAttribute('include')

		if include_attr is not None:
			include_attr_val = str(include_attr.value).lower()
			if include_attr_val == "true":
				result = False
				errors.append(f"If filename is not present, a submap cannot have an include (==true)")

		# can have x-hdl/busgroup only if interface attribute is wb*
		busgroup = node.getAttribute(['x-hdl', 'busgroup'])
		if busgroup is not None:
			busgroup_val = str(busgroup.value).lower()

			if busgroup_val == "true":
				if interface_attr is not None:
					interface_attr_val = interface_attr.value
					if not interface_attr_val.startswith('wb'):
						result = False
						errors.append(
							f"If filename is not present and x-hdl/busgroup is true, interface must be present"
							f" and be wb*")
				else:
					result = False
					errors.append(f"If filename is not present and x-hdl/busgroup is true, interface must be present"
								  f" and be wb*")
	if not result:
		reksio.warn(f"Submap {node} is not valid: \n" + "\n".join(errors))
	return result


def getMessage():
	return "Submap is not valid (see the console output)."
